Mesdames, Messieurs, voici python 3.6

Mais ne me croyez pas sur parole, on va vérifier

(présentation en avant-deuxième !)

In [6]:
import sys
print(sys.version)
3.6.0b4 (default, Nov 25 2016, 08:08:08)
[GCC 5.4.0 20160609]

Yay

Bon quoi de neuf, du coup

Les Strings formattées encore améliorées

Vous connaissez déjà la syntaxe suivante

In [7]:
language = "Python"
year = 2016

template = "Bonjour le dernier Meetup %(language)s de l'année %(year)d"

print(template % {"language": language, "year": year})
Bonjour le dernier Meetup Python de l'année 2016

Vous avez peut-être l'habitude d'utiliser

In [8]:
template = "Bonjour le dernier Meetup %s de l'année %d"
print(template % (language, year))
Bonjour le dernier Meetup Python de l'année 2016

Mais c'est long à taper.

Ça c'était en Python 2.

Vous connaissez aussi la nouvelle syntaxe

In [9]:
template = "Bonjour le dernier Meetup {language} de l'année {year}"

print(template.format(language=language, year=year))
Bonjour le dernier Meetup Python de l'année 2016

Mais c'est toujours long à taper...

Et peut-etre même savez-vous que ca permet de faire des choses merveilleuses comme

In [10]:
print("{:~^30}".format(" Bonjour Python ! "))
~~~~~~ Bonjour Python ! ~~~~~~
In [11]:
from datetime import datetime
print("{:%Y-%m-%d}".format(datetime.now()))
2016-11-28

(protip : plongez vous dans les arcanes du .format sur http://pyformat.info)

Et maintenant vous avez... (roulement de tambours)

In [12]:
f"Bonjour le dernier Meetup {language} de {year}"
Out[12]:
'Bonjour le dernier Meetup Python de 2016'
In [13]:
f"Bonjour le dernier Meetup {language} de {datetime.now():%Y}"
Out[13]:
'Bonjour le dernier Meetup Python de 2016'

Les annotations de types pour les variables

Python, circa 2014 (a.k.a Python 3.4-)

In [14]:
first_grade = 3
grades = [first_grade, 2, 5.7]

class Student:
    notes = []

    def average(self, multiplier=1):
        if not self.grades:
            return "Aucune note"

        average = sum(self.grades) / len(self.grades)
        average *= multiplier
        return "Average grade: {:.1f}".format(average)

s = Student()
s.grades = grades
print(s.average())
Average grade: 3.6

Python, circa 2015 (a.k.a Python 3.5)

In [15]:
first_grade = 3
grades = [first_grade, 2, 5.7]

class Student:
    notes = []

    def average(self, multiplier: float=1) -> str:
        if not self.grades:
            return "Aucune note"

        average = sum(self.grades) / len(self.grades)
        average *= multiplier
        return "Average grade: {:.1f}".format(average)

s = Student()
s.grades = grades
print(s.average())
Average grade: 3.6

Python, circa 2016 (a.k.a Python 3.6)

In [16]:
from typing import List

first_grade: int = 3
grades: List[float] = [first_grade, 2, 5.7]

class Student:
    notes: List[float] = []

    def average(self, multiplier: float=1) -> str:
        if not self.grades:
            return "Aucune note"

        average: float = sum(self.grades) / len(self.grades)
        average *= multiplier
        return f"Average grade: {average:.1f}"

s:Student = Student()
s.grades = grades
print(s.average())
Average grade: 3.6

Des grands nombres enfin lisibles

In [17]:
print(1_000_000_000_000_000)

print(f"{0x_FF_FF_FF_FF:X}")
1000000000000000
FFFFFFFF

Des nouvelles méthodes magiques

Pour l'héritage...

In [18]:
class PluginBase:
    subclasses = []

    def __init_subclass__(cls, **kwargs):
        super().__init_subclass__(**kwargs)
        cls.subclasses.append(cls)

class Plugin1(PluginBase):
    pass

class Plugin2(PluginBase):
    pass

print(PluginBase.subclasses)
[<class '__main__.Plugin1'>, <class '__main__.Plugin2'>]

... et pour la composition

In [19]:
class IntField:
    # this is the new initializer:
    def __set_name__(self, owner, name):
        self.model = owner
        self.name = name

    def whats_your_name(self):
        print(f"{self.model} m'a nommé {self.name}")

class ModelA:
    value_a = IntField()

class ModelB:
    value_b = IntField()
In [20]:
ModelA().value_a.whats_your_name()
ModelB().value_b.whats_your_name()
<class '__main__.ModelA'> m'a nommé value_a
<class '__main__.ModelB'> m'a nommé value_b

Toujours plus d'asynchrone

L'API d'asyncio est stabilisée et on peut maintenant créer des générateurs asynchrones

pathlib amélioré !

In [21]:
import os, pathlib

path = pathlib.Path() / ".."

print(os.listdir(path))
['Spotify-AdKiller', 'beautifuldjango.github.io', 'agency-jekyll-theme', 'django', 'deps', 'theano', 'test', 'req.txt', 'jupyter']
In [22]:
path = path / "jupyter" / "Python 3.6.ipynb"

print(open(path))
<_io.TextIOWrapper name='../jupyter/Python 3.6.ipynb' mode='r' encoding='UTF-8'>
In [23]:
print(path.parent)
../jupyter
In [24]:
print(path.suffix)
.ipynb
In [25]:
print(path.stem)
Python 3.6

Python connait tau !

In [26]:
from math import tau, pi, cos, sin

print(tau == 2 * pi)
print(f"{cos(tau):.2f}, {sin(tau):.2f}")
True
1.00, -0.00

Les dictionnaires sont maintenant ordonnés

Bonus : ils sont plus compacts en mémoire !

In [27]:
list({i: i for i in range(100)}) == list(range(100))
Out[27]:
True

Le module secrets pour générer des clés

In [28]:
import secrets
print(f"{secrets.randbits(2048):X}")
F68C2A8EB0518742D521FF66DF24E464FC54E2F03BE9C93A2400862907D391BD8A884B22FBCF40E187A3A218A374B178542DD259F1F25C233DD2A0BA33438B775EAAE3EF689CD31249EC36CAB9EFB7E2EDDC2B941F0875123A78FCA7A1C733B62FD77E80740F94809527BF57BFB53774D02DD267D6E4BA812DAFCE2118FF369948FB22E7B60A72546D761D1D35361656C95D7ADF07E79CAE404FA8B9F7A208895EEBE888151B0E702D25A1D9678A6948C739573B1D02534315B6618A92DCDA56AB327B66FD262C125124B8C29042385D6A56894A0B0AB20C9D65F73965CBF33FECFD82B60E46A2190D717F12935E1973322FEB7FF163BB737B5B785AB9F4BA04

En route pour la 3.7 !

Merci de votre attention. Des questions ?

Novembre 2016 - Joachim Jablon (@ewjoachim) - PeopleDoc (on recrute !)

Réalisation technique des slides: Jupyter Notebook et Reveal.js